package com.cyx.spring.aop;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.cyx.spring.context.ApplicationContextUtils;
import com.cyx.spring.context.BeanDefinition;
import com.cyx.spring.context.BeanPostProcessor;
import com.cyx.spring.context.ConfigurableApplicationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * AnnotationProxyBeanPostProcessor
 *
 * @author yongxiang
 * @date 2024/10/24 14:44
 * @desc
 */
public abstract class AnnotationProxyBeanPostProcessor<T extends Annotation> implements BeanPostProcessor {
    private Class<T> annotationType;
    private Map<String, Object> originBeans = new HashMap<>();

    public AnnotationProxyBeanPostProcessor() {
         this.annotationType = getParameterizedType();
    }

    @SuppressWarnings("unchecked")
    private Class<T> getParameterizedType() {
        Type type = getClass().getGenericSuperclass();
        if (!(type instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " does not have parameterized type.");
        }
        ParameterizedType pt = (ParameterizedType) type;
        Type[] types = pt.getActualTypeArguments();
        if (types.length != 1) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " has more than 1 parameterized types.");
        }
        Type r = types[0];
        if (!(r instanceof Class<?>)) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " does not have parameterized type of class.");
        }
        return (Class<T>) r;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        Object obj = bean;
        //创建代理对象
        T annotation = bean.getClass().getAnnotation(annotationType);
        if (annotation != null){
            //创建代理对象 获取拦截器
            String handlerName = null;
            try {
                handlerName = (String) annotation.annotationType().getMethod("value").invoke(annotation);
            } catch (Exception e) {
                throw new RuntimeException("获取拦截器名称失败:@"+annotationType.getSimpleName());
            }
            if (StrUtil.isBlank(handlerName)){
                throw new RuntimeException("请配置拦截器:@" + annotationType.getSimpleName());
            }
            obj = createProxyBean(bean, handlerName,beanName);
            if (obj != bean){
                originBeans.put(beanName,bean);
            }
            return obj;
        }
        return obj;
    }

    private Object createProxyBean(Object bean, String handlerName, String beanName) {
        ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) ApplicationContextUtils.getApplicationContext();
        BeanDefinition beanDefinition = applicationContext.findBeanDefinition(handlerName);
        if (beanDefinition == null){
            throw new RuntimeException("the handle is miss:"+handlerName);
        }
        Object handler = beanDefinition.getInstance();
        if (handler == null){
            //创建即可
            handler = applicationContext.createBeanAsEarlySingleton(beanDefinition);
        }
        return ProxyResolver.getInstance().createProxy(bean, (InvocationHandler) handler);
    }


    @Override
    public Object postProcessOnSetProperty(Object bean, String beanName) {
        Object o = originBeans.get(beanName);
        return Objects.isNull(o)?bean:o;
    }
}
